<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文主要是进程通信——管道的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV05-05-进程通信-02-管道">
<meta property="og:url" content="https://sumumm.github.io/post/3873081f.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="本文主要是进程通信——管道的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/image-20220603141756784.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/image-20220603145945007.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/image-20220603150642771.png">
<meta property="article:published_time" content="2023-07-02T13:52:20.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:56.994Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV05-操作系统">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/image-20220603141756784.png">


<link rel="canonical" href="https://sumumm.github.io/post/3873081f.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://sumumm.github.io/post/3873081f.html","path":"post/3873081f.html","title":"LV05-05-进程通信-02-管道"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV05-05-进程通信-02-管道 | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81Linux-%E7%AE%A1%E9%81%93"><span class="nav-text">一、Linux 管道</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E6%97%A0%E5%90%8D%E7%AE%A1%E9%81%93"><span class="nav-text">1. 无名管道</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E6%9C%89%E5%90%8D%E7%AE%A1%E9%81%93"><span class="nav-text">2. 有名管道</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%88%9B%E5%BB%BA%E6%9C%89%E5%90%8D%E7%AE%A1%E9%81%93"><span class="nav-text">2.1 创建有名管道</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E5%91%BD%E4%BB%A4%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1.1 命令说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E6%95%B0%E6%8D%AE%E8%AF%BB%E5%86%99"><span class="nav-text">2.2 数据读写</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-%E5%91%BD%E4%BB%A4%E8%AF%B4%E6%98%8E"><span class="nav-text">2.2.1 命令说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.2.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E7%AE%A1%E9%81%93%E5%A4%A7%E5%B0%8F%E6%9F%A5%E7%9C%8B"><span class="nav-text">3. 管道大小查看</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E7%AE%A1%E9%81%93%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="nav-text">二、管道的概念</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E6%97%A0%E5%90%8D%E7%AE%A1%E9%81%93"><span class="nav-text">三、无名管道</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E6%97%A0%E5%90%8D%E7%AE%A1%E9%81%93%E5%88%9B%E5%BB%BA"><span class="nav-text">1. 无名管道创建</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-pipe"><span class="nav-text">1.1 pipe() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.1.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E6%97%A0%E5%90%8D%E7%AE%A1%E9%81%93%E8%AF%BB%E5%86%99"><span class="nav-text">2. 无名管道读写</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-read"><span class="nav-text">2.1 read() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">2.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-write"><span class="nav-text">2.2 write() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">2.2.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-%E7%AE%A1%E9%81%93%E8%AF%BB%E5%86%99%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.3 管道读写实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E7%88%B6%E5%AD%90%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1"><span class="nav-text">3. 父子进程通信</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-%E7%88%B6%E8%BF%9B%E7%A8%8B%E5%88%9B%E5%BB%BA%E7%AE%A1%E9%81%93"><span class="nav-text">3.1 父进程创建管道</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-fork-%E5%87%BA%E5%AD%90%E8%BF%9B%E7%A8%8B"><span class="nav-text">3.2 fork 出子进程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-%E6%B7%B7%E4%B9%B1%E9%81%BF%E5%85%8D"><span class="nav-text">3.3 混乱避免</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-4-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.4 使用实例</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-1-%E5%AE%9E%E4%BE%8B1"><span class="nav-text">3.4.1 实例1</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-2-%E5%AE%9E%E4%BE%8B2"><span class="nav-text">3.4.2 实例2</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E7%AE%A1%E9%81%93%E7%9A%84%E5%A4%A7%E5%B0%8F"><span class="nav-text">4. 管道的大小</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-%E6%9C%80%E5%A4%9A%E5%86%99%E5%A4%9A%E5%B0%91%E5%AD%97%E8%8A%82%EF%BC%9F"><span class="nav-text">4.1 最多写多少字节？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-%E8%AF%BB4k-1%E4%B8%AA%E5%AD%97%E8%8A%82%EF%BC%9F"><span class="nav-text">4.2 读4k-1个字节？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-3-%E8%AF%BB4K%E4%B8%AA%E5%AD%97%E8%8A%82%EF%BC%9F"><span class="nav-text">4.3 读4K个字节？</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-%E6%97%A0%E5%90%8D%E7%AE%A1%E9%81%93%E7%89%B9%E6%80%A7"><span class="nav-text">5. 无名管道特性</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#5-1-%E8%AF%BB%E5%86%99%E7%AB%AF%E5%9B%BA%E5%AE%9A"><span class="nav-text">5.1 读写端固定</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-1-%E8%AF%B4%E6%98%8E"><span class="nav-text">5.1.1 说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-2-%E6%B5%8B%E8%AF%95%E5%AE%9E%E4%BE%8B"><span class="nav-text">5.1.2 测试实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-2-%E8%AF%BB%E7%AE%A1%E9%81%93%E7%89%B9%E6%80%A7"><span class="nav-text">5.2 读管道特性</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#5-2-1-%E8%AF%B4%E6%98%8E"><span class="nav-text">5.2.1 说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">5.2.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-3-%E5%86%99%E7%AE%A1%E9%81%93%E7%89%B9%E6%80%A7"><span class="nav-text">5.3 写管道特性</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#5-3-1-%E8%AF%B4%E6%98%8E"><span class="nav-text">5.3.1 说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-3-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">5.3.2 使用实例</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81%E6%9C%89%E5%90%8D%E7%AE%A1%E9%81%93"><span class="nav-text">四、有名管道</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E6%9C%89%E5%90%8D%E7%AE%A1%E9%81%93%E5%88%9B%E5%BB%BA"><span class="nav-text">1. 有名管道创建</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-mkfifo"><span class="nav-text">1.1 mkfifo() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">1.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">1.1.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E6%9C%89%E5%90%8D%E7%AE%A1%E9%81%93%E6%89%93%E5%BC%80"><span class="nav-text">2. 有名管道打开</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-open"><span class="nav-text">2.1 open() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">2.1.1 函数说明</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E"><span class="nav-text">2.2 使用说明</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E6%9C%89%E5%90%8D%E7%AE%A1%E9%81%93%E8%AF%BB%E5%86%99"><span class="nav-text">3. 有名管道读写</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-%E8%AF%BB%E5%86%99%E5%87%BD%E6%95%B0"><span class="nav-text">3.1 读写函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.2 使用实例</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/3873081f.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV05-05-进程通信-02-管道 | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV05-05-进程通信-02-管道
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-07-02 21:52:20" itemprop="dateCreated datePublished" datetime="2023-07-02T21:52:20+08:00">2023-07-02</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/" itemprop="url" rel="index"><span itemprop="name">01HQ课程体系</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" itemprop="url" rel="index"><span itemprop="name">LV05-操作系统</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>12k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>45 分钟</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>本文主要是进程通信——管道的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/ -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150px>Windows</td>        <td align="left">windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu16.04的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 16 Pro</td>        <td align="left">16.2.3 build-19376536</td>      </tr>    <tr>        <td align="center">SecureCRT</td>        <td align="left">Version 8.7.2 (x64 build 2214)   -   正式版-2020年5月14日</td>      </tr>    <tr>        <td align="center">开发板</td>        <td align="left">正点原子 i.MX6ULL Linux阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.15(NXP官方提供)</td>      </tr>    <tr>        <td align="center">STM32开发板</td>        <td align="left">正点原子战舰V3(STM32F103ZET6)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <table>    <tr><td align="center">参考方向  </td><td align="center">参考原文</td></tr>    <tr><td align="left">---</td><td align="left"><a href="" target="_blank">--- <i class="fa fa-external-link-alt"></i> </a></td></tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150>---</td>        <td align="left"><a href="" target="_blank">---<i class="fa fa-external-link-alt"></i> </a></td>      </tr></table>
              </div>
            </details>

<h1 id="一、Linux-管道"><a href="#一、Linux-管道" class="headerlink" title="一、Linux 管道"></a><font size=3>一、Linux 管道</font></h1><h2 id="1-无名管道"><a href="#1-无名管道" class="headerlink" title="1. 无名管道"></a><font size=3>1. 无名管道</font></h2><p>我们前边在学习<code>Linux</code>命令的时候，有学习过这么一个符号<code>|</code>，这就是管道，例如，</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -elf | grep a.out</span><br></pre></td></tr></table></figure>

<p>它的功能是将前一个命令（<code>ps -elf</code>）的输出，作为后一个命令（<code>grep a.out</code>）的输入，不难看出<strong>管道传输数据是单向的</strong>，如果想相互通信，我们需要创建两个管道才行。上面这种管道是没有名字，所以<code>|</code>表示的管道称为<strong>匿名管道</strong>，也可以叫<strong>无名管道</strong>，用完了就销毁。</p>
<h2 id="2-有名管道"><a href="#2-有名管道" class="headerlink" title="2. 有名管道"></a><font size=3>2. 有名管道</font></h2><p>管道还有另外一个类型是<strong>命名管道</strong>，也被叫做 <code>FIFO</code>，也可以叫有名管道。因为数据是先进先出的传输方式。</p>
<h3 id="2-1-创建有名管道"><a href="#2-1-创建有名管道" class="headerlink" title="2.1 创建有名管道"></a><font size=3>2.1 创建有名管道</font></h3><h4 id="2-1-1-命令说明"><a href="#2-1-1-命令说明" class="headerlink" title="2.1.1 命令说明"></a><font size=3>2.1.1 命令说明</font></h4><p>在使用命名管道前，先需要通过 <code>mkfifo</code> 命令来创建，并且指定管道名字，可以在终端输入以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkfifo &lt;管道名称&gt;</span><br></pre></td></tr></table></figure>

<h4 id="2-1-2-使用实例"><a href="#2-1-2-使用实例" class="headerlink" title="2.1.2 使用实例"></a><font size=3>2.1.2 使用实例</font></h4><p>我们可以执行以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkfifo myFifo</span><br></pre></td></tr></table></figure>

<p>要是在<code>Windows</code>共享文件夹目录(<code>/mnt/hgfs/Sharedfiles</code>)下创建的话可能会收到如下提示：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkfifo: 无法创建先进先出文件&#x27;myFifo&#x27;: 没有那个文件或目录</span><br></pre></td></tr></table></figure>

<p>归根结底是因为用的是共享文件夹，而<code>Windows</code>的文件系统又不支持管道文件。创建的管道文件路径必须设为<code>linux</code>的本地文件夹。所以我们不要在共享目录下创建就可以啦，创建完成后我们使用<code>ls -alh</code>查看一下创建的文件详细信息：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">总用量 8.0K</span><br><span class="line">drwxrwxr-x  2 hk hk 4.0K  6月  3 14:38 .</span><br><span class="line">drwxr-x--- 22 hk hk 4.0K  6月  3 14:03 ..</span><br><span class="line">prw-rw-r--  1 hk hk    0  6月  3 14:38 myFifo</span><br><span class="line">-rw-rw-r--  1 hk hk    0  4月 23 22:04 test.vim</span><br></pre></td></tr></table></figure>

<p>会发现，有名管道文件类型为<code>p</code>，也就是 <code>pipe</code>（管道） 的意思。</p>
<h3 id="2-2-数据读写"><a href="#2-2-数据读写" class="headerlink" title="2.2 数据读写"></a><font size=3>2.2 数据读写</font></h3><h4 id="2-2-1-命令说明"><a href="#2-2-1-命令说明" class="headerlink" title="2.2.1 命令说明"></a><font size=3>2.2.1 命令说明</font></h4><ul>
<li>向管道写入数据</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;data&quot; &gt; 已创建的管道名称 # 可以包含路径</span><br></pre></td></tr></table></figure>

<ul>
<li>从管道读取数据</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat &lt; 已创建的管道名称  # 可以包含路径</span><br></pre></td></tr></table></figure>

<p>【注意事项】我们必须在管道所在的目录下执行上边的读写命令，或者就是指明创建的管道的路径。</p>
<h4 id="2-2-2-使用实例"><a href="#2-2-2-使用实例" class="headerlink" title="2.2.2 使用实例"></a><font size=3>2.2.2 使用实例</font></h4><p>下边的演示，在管道文件myFifo所在的目录中进行。我们在终端执行以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;fanhua&quot; &gt; myFifo</span><br></pre></td></tr></table></figure>

<p>输入命令后，按下回车，我们会发现终端停住了，这是因为管道里的内容没有被读取，只有当管道里的数据被读完后，命令才可以正常退出。我们开启另一个终端，输入以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat &lt; myFifo</span><br></pre></td></tr></table></figure>

<p>然后，终端会有以下数据输出：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fanhua</span><br></pre></td></tr></table></figure>

<p>这个时候，我们会发现，写入数据的终端命令正常退出了，管道中的数据已经读取了，我们再读会出现什么情况？管道中没有数据的时候再执行一次读取命令，那么这个终端就会停住，直到另一个终端向管道写入数据，便会直接读取数据然后退出。</p>
<p>我们可以看出，<strong>管道这种通信方式效率低，不适合进程间频繁地交换数据</strong>。当然，它的好处就是简单，同时也我们很容易得知管道里的数据已经被另一个进程读取了。</p>
<h2 id="3-管道大小查看"><a href="#3-管道大小查看" class="headerlink" title="3. 管道大小查看"></a><font size=3>3. 管道大小查看</font></h2><p>那么既然管道是一种文件，它的最大大小是多少呢？我们可以使用如下命令查看：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ulimit -a</span><br></pre></td></tr></table></figure>

<p>然后终端会有如下信息提示：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">real-time non-blocking time  (microseconds, -R) unlimited</span><br><span class="line">core file size              (blocks, -c) 0</span><br><span class="line">data seg size               (kbytes, -d) unlimited</span><br><span class="line">scheduling priority                 (-e) 0</span><br><span class="line">file size                   (blocks, -f) unlimited</span><br><span class="line">pending signals                     (-i) 15308</span><br><span class="line">max locked memory           (kbytes, -l) 498501</span><br><span class="line">max memory size             (kbytes, -m) unlimited</span><br><span class="line">open files                          (-n) 1024</span><br><span class="line">pipe size                (512 bytes, -p) 8</span><br><span class="line">POSIX message queues         (bytes, -q) 819200</span><br><span class="line">real-time priority                  (-r) 0</span><br><span class="line">stack size                  (kbytes, -s) 8192</span><br><span class="line">cpu time                   (seconds, -t) unlimited</span><br><span class="line">max user processes                  (-u) 15308</span><br><span class="line">virtual memory              (kbytes, -v) unlimited</span><br><span class="line">file locks                          (-x) unlimited</span><br></pre></td></tr></table></figure>

<p>其中有一个<code>pipe size</code>，可以看到是<code>8x521byte=4k</code>。但是当我们查看<code>man</code>手册的时候，使用如下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man 7 pipe</span><br></pre></td></tr></table></figure>

<p>然后找到<code>Pipe capacity</code>部分，有如下说明：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">A pipe  has a limited capacity.  If the pipe is full, then a write(2) will block or fail, depending on whether the O_NONBLOCK  flag  is  set (see  below).  Different implementations have different limits for the pipe capacity.  Applications should not rely on a particular capacity: an  application  should be designed so that a reading process consumes data as soon as it is available, so that a writing  process  does  not remain blocked.</span><br><span class="line"></span><br><span class="line">In  Linux  versions before 2.6.11, the capacity of a pipe was the same as the system page size (e.g., 4096  bytes  on  i386).   Since  Linux 2.6.11,  the pipe capacity is 16 pages (i.e., 65,536 bytes in a system with a page size of 4096 bytes).  Since Linux 2.6.35, the default pipe capacity  is  16  pages, but the capacity can be queried and set using the fcntl(2) F_GETPIPE_SZ and F_SETPIPE_SZ operations.   See  fcntl(2) for more information.</span><br></pre></td></tr></table></figure>

<p>其实看的不是很明白，后边挺老师讲的时候，说最大是<code>64K</code>。于是便查阅了很多资料吗，了解到管道容量分为<code>pipe capacity </code>和 <code>pipe_buf </code>。这两者的区别在于<code>pipe_buf</code>定义的是内核管道缓冲区的大小，这个值的大小是由内核设定的，这个值仅需一条命令就可以查到；而<code>pipe capacity</code>指的是管道的最大值，即容量，是内核内存中的一个缓冲区。</p>
<h1 id="二、管道的概念"><a href="#二、管道的概念" class="headerlink" title="二、管道的概念"></a><font size=3>二、管道的概念</font></h1><p>上线了解了linux中的管道的相关操作，接下来我们来学习一下管道的概念。</p>
<p>管道是<code>UNIX</code>系统上最古老的<code>IPC</code>方法，它在<code>20</code>世纪<code>70</code>年代早期<code>UNIX</code>的第三个版本上就出现了。把一个进程连接到另一个进程的数据流称为<strong>管道</strong>，管道被抽象成一个文件，称为管道文件(<code>pipe</code>)。</p>
<p>管道可以分为两种：无名(匿名)管道和有名管道。两者的特点如下：</p>
<div class="tabs" id="tabname1"><ul class="nav-tabs"><li class="tab active"><a href="#tabname1-1">无名管道</a></li><li class="tab"><a href="#tabname1-2">有名管道</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname1-1"><ul>
<li><p>只能用于<strong>具有亲缘关系的进程之间的通信</strong>（父子进程，兄弟进程）。</p>
</li>
<li><p>是单工的通信模式，具有固定的读端和写端，只能一端读，一端写（程序实现设计好）。</p>
</li>
<li><p>无名管道创建时会返回两个文件描述符，分别用于读写管道。</p>
</li>
<li><p>管道可以用于多于<code>2</code>个进程共享。</p>
</li>
</ul></div><div class="tab-pane" id="tabname1-2"><ul>
<li><p>有名管道可以<strong>使非亲缘的两个进程互相通信</strong>；</p>
</li>
<li><p>通过路径名来操作，在文件系统中可见，但内容存放在内存中；</p>
</li>
<li><p>文件<code>IO</code>来操作有名管道；</p>
</li>
<li><p>遵循先进先出规则；</p>
</li>
<li><p>不支持<code>leek</code>操作；</p>
</li>
<li><p>单工读写。</p>
</li>
</ul></div></div></div>

<p>【注意事项】不管是匿名管道还是命名管道，进程写入的<strong>数据都是缓存在内核</strong>中，另一个进程读取数据时候自然也是从内核中获取，同时通信数据都遵循<strong>先进先出</strong>原则，不支持 <code>lseek</code> 之类的文件定位操作。另外他们都是单工读写的，若要实现双向的数据传输，可以使用两个管道。</p>
<h1 id="三、无名管道"><a href="#三、无名管道" class="headerlink" title="三、无名管道"></a><font size=3>三、无名管道</font></h1><h2 id="1-无名管道创建"><a href="#1-无名管道创建" class="headerlink" title="1. 无名管道创建"></a><font size=3>1. 无名管道创建</font></h2><h3 id="1-1-pipe"><a href="#1-1-pipe" class="headerlink" title="1.1 pipe() "></a><font size=3>1.1 pipe() </font></h3><h4 id="1-1-1-函数说明"><a href="#1-1-1-函数说明" class="headerlink" title="1.1.1 函数说明"></a><font size=3>1.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man pipe </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">pipe</span><span class="params">(<span class="type">int</span> pipefd[<span class="number">2</span>])</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数创建一个无名管道，创建之后会产生两个文件描述符，就相当于直接打开了可以直接使用，使用完毕后会自动销毁。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>pipefd[2]</code>：<code>int</code>类型，是一个大小为<code>2</code>的数组，<code>pipefd[0]</code>和<code>pipefd[1]</code>表示两个文件描述符，分别代表管道的两端，一般代表含义如下：</li>
</ul>
<table>
    <tr>
        <td align="center" width=150px>pipefd[0]</td>
        <td align="left">管道读端</td>
    </tr>
    <tr>
        <td align="center" width=150>pipefd[1]</td>
        <td align="left">管道写端</td>  
    </tr>
</table>

<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line">pipe(pfd);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>创建的匿名管道是特殊的文件，<strong>只存在于内存，不存于文件系统中</strong>。</p>
<h4 id="1-1-2-使用实例"><a href="#1-1-2-使用实例" class="headerlink" title="1.1.2 使用实例"></a><font size=3>1.1.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[0]=%d,pfd[1]=%d\n&quot;</span>,pfd[<span class="number">0</span>],pfd[<span class="number">1</span>]);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pfd[0]=3,pfd[1]=4</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="2-无名管道读写"><a href="#2-无名管道读写" class="headerlink" title="2. 无名管道读写"></a><font size=3>2. 无名管道读写</font></h2><h3 id="2-1-read"><a href="#2-1-read" class="headerlink" title="2.1 read() "></a><font size=3>2.1 read() </font></h3><h4 id="2-1-1-函数说明"><a href="#2-1-1-函数说明" class="headerlink" title="2.1.1 函数说明"></a><font size=3>2.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 read</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">read</span><span class="params">(<span class="type">int</span> fd, <span class="type">void</span> *buf, <span class="type">size_t</span> count)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数从文件描述符指向的文件中读指定字节数据。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>fd</code>：<code>int</code>类型，表示文件描述符。</li>
<li><code>buf</code>：<code>void *</code>类型，表示接收数据的缓冲区。</li>
<li><code>count</code>：<code>size_t</code>类型，为需要读取的字节数，不应超过<code>buf</code>的长度。</li>
</ul>
<p><strong>【返回值】</strong><code>ssize_t</code>类型，成功返回读取的字节数；失败返回<code>-1</code>, 错误代码存入<code>errno</code> 中, 而文件读写位置则无法预期；读到文件末尾时或者<code>count</code>为<code>0</code>时，将返回<code>0</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">char</span> buf[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">pipe(pfd);</span><br><span class="line">read(pfd[<span class="number">0</span>], buf, <span class="keyword">sizeof</span>(buf)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）读取过程中，未读完<code>count</code>字节时，若遇到换行，则会一起读取。</p>
<p>（2）对于⼀个数组，总是要自动分配⼀个<code>\0</code>作为结束，所以实际有效的<code>buf</code>长度就成为<code>sizeof(buf) - 1</code>了，最好就是在读取完成后自己加上一个<code>\0</code>，以防止后边打印出现乱码的情况。</p>
<p>（3）文件读写位置会随读取到的字节移动。</p>
<h4 id="2-1-2-使用实例-1"><a href="#2-1-2-使用实例-1" class="headerlink" title="2.1.2 使用实例"></a><font size=3>2.1.2 使用实例</font></h4><p>暂无。</p>
<h3 id="2-2-write"><a href="#2-2-write" class="headerlink" title="2.2 write() "></a><font size=3>2.2 write() </font></h3><h4 id="2-2-1-函数说明"><a href="#2-2-1-函数说明" class="headerlink" title="2.2.1 函数说明"></a><font size=3>2.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 3 write  </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">write</span><span class="params">(<span class="type">int</span> fd, <span class="type">const</span> <span class="type">void</span> *buf, <span class="type">size_t</span> count)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数会将指定字节数据写入到文件描述符所指向的文件中去。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>fd</code>：<code>int</code>类型，表示文件描述符。</li>
<li><code>buf</code>：<code>void *</code>类型，表示要写入数据的缓冲区。</li>
<li><code>count</code>：<code>size_t</code>类型，为需要读取的字节数。</li>
</ul>
<p><strong>【返回值】</strong><code>ssize_t</code>类型，成功返回实际写入字节数，失败返回<code>-1</code>, 错误代码存入<code>errno</code> 中。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">char</span> buf[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">pipe(pfd);</span><br><span class="line"><span class="built_in">strcpy</span>(buf,<span class="string">&quot;fanhua！&quot;</span>);</span><br><span class="line">write(pfd[<span class="number">1</span>], buf, <span class="built_in">strlen</span>(buf));</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>数据写入完毕后，文件指针指向文件尾部，此时直接读取文件，则什么也读不到，可以使用后边的函数移动指针，再进行读取。</p>
<h4 id="2-2-2-使用实例-1"><a href="#2-2-2-使用实例-1" class="headerlink" title="2.2.2 使用实例"></a><font size=3>2.2.2 使用实例</font></h4><p>暂无。</p>
<h3 id="2-3-管道读写实例"><a href="#2-3-管道读写实例" class="headerlink" title="2.3 管道读写实例"></a><font size=3>2.3 管道读写实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep  pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> READPIPE 0  <span class="comment">/* 管道读 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> WRITEPIPE 1 <span class="comment">/* 管道写 */</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">char</span> buff[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[READPIPE]=%d,pfd[WRITEPIPE]=%d\n&quot;</span>,pfd[READPIPE],pfd[WRITEPIPE]);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line"></span><br><span class="line">		<span class="built_in">strcpy</span>(buff,<span class="string">&quot;fanhua！&quot;</span>);<span class="comment">/* 拷贝字符串到字符数组 */</span></span><br><span class="line"></span><br><span class="line">		ret = write(pfd[WRITEPIPE], buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Write %d Byte!\n&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">		ret = read(pfd[READPIPE], buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">		<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;read pipe=%s, ret = %d\n&quot;</span>, buff, ret);</span><br><span class="line">		&#125;</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">pfd[READPIPE]=3,pfd[WRITEPIPE]=4</span><br><span class="line">Write 9 Byte!</span><br><span class="line">read pipe=fanhua！, ret = 9</span><br><span class="line">Write 9 Byte!</span><br><span class="line">read pipe=fanhua！, ret = 9</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边都是循环的了......</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p>【注意事项】这里老师讲的时候好像说一个进程不能既写又读，但是自己测试的时候貌似既可以写又可以读。</p>
<h2 id="3-父子进程通信"><a href="#3-父子进程通信" class="headerlink" title="3. 父子进程通信"></a><font size=3>3. 父子进程通信</font></h2><p>上边我们已经创建了一个管道了，<strong>所谓的管道，其实就是内核里面的一串缓存</strong>。从管道的一段写入的数据，实际上是缓存在内核中的，另一端读取，也就是从内核中读取这段数据。另外，管道传输的数据是无格式的流且大小受限。</p>
<h3 id="3-1-父进程创建管道"><a href="#3-1-父进程创建管道" class="headerlink" title="3.1 父进程创建管道"></a><font size=3>3.1 父进程创建管道</font></h3><img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/image-20220603141756784.png" alt="image-20220603141756784" style="zoom: 50%;" />

<p>我们在一个进程中创建一个无名管道，会产生两个文件描述符，分别代表读写，如上图所示，并且是单向通信的，只能从写端写入，然后从读端读取，遵循先进先出的原则。</p>
<h3 id="3-2-fork-出子进程"><a href="#3-2-fork-出子进程" class="headerlink" title="3.2 fork 出子进程"></a><font size=3>3.2 fork 出子进程</font></h3><p>上边在父进程创建管道，那么再创建子进程的时候会变成什么样子呢？</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/image-20220603145945007.png" alt="image-20220603145945007" style="zoom:40%;" />



<p>前边学习进程的创建的时候，知道子进程会获得父进程所有文件描述符的副本，所以在创建子进程后，会出出现上图的情况。</p>
<h3 id="3-3-混乱避免"><a href="#3-3-混乱避免" class="headerlink" title="3.3 混乱避免"></a><font size=3>3.3 混乱避免</font></h3><p>可是上边的子进程和父进程共享文件描述后，在对管道读写的时候会出现混乱的，管道只能一端写入，另一端读出，而父进程和子进程都可以同时写入，也都可以读出。那么，为了避免这种情况，通常的做法是，一个进程用来写入，那么久关闭它的读端，另一个进程用来读取数据，那么就关闭它的写端，于是就会出现下边的情况：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-02-%E7%AE%A1%E9%81%93/img/image-20220603150642771.png" alt="image-20220603150642771" style="zoom:43%;" />

<h3 id="3-4-使用实例"><a href="#3-4-使用实例" class="headerlink" title="3.4 使用实例"></a><font size=3>3.4 使用实例</font></h3><h4 id="3-4-1-实例1"><a href="#3-4-1-实例1" class="headerlink" title="3.4.1 实例1"></a><font size=3>3.4.1 实例1</font></h4><p>这个实例是一个父进程一个子进程之间通过无名管道通信。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">char</span> buff[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="comment">/* 定义一个 pid_t 类型变量用于保存进程号*/</span></span><br><span class="line">	<span class="type">pid_t</span> pid;</span><br><span class="line">	<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[0]=%d,pfd[1]=%d\n&quot;</span>,pfd[<span class="number">0</span>],pfd[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 2. 创建一个父子进程 */</span></span><br><span class="line">	pid = fork();</span><br><span class="line">	<span class="comment">/* 3. 父子进程区分执行不同内容 */</span></span><br><span class="line">	<span class="comment">/* 进程创建错误 */</span></span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 父进程 */</span></span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭父进程中管道读取端 */</span></span><br><span class="line">		close(pfd[<span class="number">0</span>]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="comment">/* 拷贝字符串到字符数组 */</span></span><br><span class="line">			<span class="built_in">strcpy</span>(buff,<span class="string">&quot;fanhua&quot;</span>);</span><br><span class="line">			<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line">			ret = write(pfd[<span class="number">1</span>], buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">			<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(<span class="string">&quot;Father process write pipe=%s\n&quot;</span>, buff);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="comment">/* 休眠1s */</span></span><br><span class="line">			sleep(<span class="number">1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 子进程 */</span></span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭子进程中管道的写入端 */</span></span><br><span class="line">		close(pfd[<span class="number">1</span>]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="comment">/* 从字符数组中读取数据 */</span></span><br><span class="line">			ret = read(pfd[<span class="number">0</span>] , buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">			<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(<span class="string">&quot;Child process read pipe=%s\n&quot;</span>, buff);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">pfd[0]=3,pfd[1]=4</span><br><span class="line">Father process write pipe=fanhua</span><br><span class="line">Child process read pipe=fanhua</span><br><span class="line">Father process write pipe=fanhua</span><br><span class="line">Child process read pipe=fanhua</span><br><span class="line">Father process write pipe=fanhua</span><br><span class="line">Child process read pipe=fanhua</span><br><span class="line">Father process write pipe=fanhua</span><br><span class="line">Child process read pipe=fanhua</span><br><span class="line">Father process write pipe=fanhua</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h4 id="3-4-2-实例2"><a href="#3-4-2-实例2" class="headerlink" title="3.4.2 实例2"></a><font size=3>3.4.2 实例2</font></h4><p>这个实例是一个父进程两个子进程之间通过无名管道通信。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> READPIPE 0  <span class="comment">/* 管道读 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> WRITEPIPE 1 <span class="comment">/* 管道写 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">char</span> buff[<span class="number">40</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="comment">/* 定义一个 pid_t 类型变量用于保存进程号*/</span></span><br><span class="line">	<span class="type">pid_t</span> pid;</span><br><span class="line">	<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[READPIPE]=%d,pfd[WRITEPIPE]=%d\n&quot;</span>,pfd[READPIPE],pfd[WRITEPIPE]);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 2. 创建一个父进程两个子进程 A-&gt;B A-&gt;C */</span></span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i&lt;<span class="number">2</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		pid = fork();<span class="comment">/* 注意父子进程后续都会执行该句下边的所有程序 */</span></span><br><span class="line">		<span class="comment">/* 3. 父子进程区分执行不同内容 */</span></span><br><span class="line">		<span class="comment">/* 进程创建错误 */</span></span><br><span class="line">		<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">			<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">/* 父进程 */</span></span><br><span class="line">		<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)</span><br><span class="line">		&#123;</span><br><span class="line"></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">/* 子进程 */</span></span><br><span class="line">		<span class="keyword">else</span></span><br><span class="line">		&#123;</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span>(i == <span class="number">0</span>)<span class="comment">/* 第一个子进程创建完成，执行到这里 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭管道读取端 */</span></span><br><span class="line">		close(pfd[READPIPE]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="comment">/* 拷贝字符串到字符数组 */</span></span><br><span class="line">			<span class="built_in">strcpy</span>(buff,<span class="string">&quot;This is 1 process!&quot;</span>);</span><br><span class="line">			<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line">			write(pfd[WRITEPIPE], buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">			<span class="comment">/* 休眠 */</span></span><br><span class="line">			sleep(<span class="number">1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span>(i == <span class="number">1</span>)<span class="comment">/* 第二个子进程创建完成，执行到这里 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭管道读取端 */</span></span><br><span class="line">		close(pfd[READPIPE]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="comment">/* 拷贝字符串到字符数组 */</span></span><br><span class="line">			<span class="built_in">strcpy</span>(buff,<span class="string">&quot;This is 2 process!&quot;</span>);</span><br><span class="line">			<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line">			write(pfd[WRITEPIPE], buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">			<span class="comment">/* 休眠 900 ms */</span></span><br><span class="line">			usleep(<span class="number">900000</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span>(i == <span class="number">2</span>)<span class="comment">/* 父进程，执行到这里 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭管道写入端 */</span></span><br><span class="line">		close(pfd[WRITEPIPE]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="comment">/* 读之前先清空 */</span></span><br><span class="line">			<span class="built_in">memset</span>(buff, <span class="number">0</span>, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">			<span class="comment">/* 从字符数组中读取数据 */</span></span><br><span class="line">			ret = read(pfd[READPIPE], buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">			<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(<span class="string">&quot;father read pipe=%s\n&quot;</span>,buff);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">pfd[READPIPE]=3,pfd[WRITEPIPE]=4</span><br><span class="line">father read pipe=This is 2 process!</span><br><span class="line">father read pipe=This is 1 process!</span><br><span class="line">father read pipe=This is 2 process!</span><br><span class="line">father read pipe=This is 1 process!</span><br><span class="line">father read pipe=This is 2 process!</span><br><span class="line">father read pipe=This is 1 process!</span><br><span class="line">father read pipe=This is 2 process!</span><br></pre></td></tr></table></figure><p>可以发现，两个子进程向管道写入数据，都会被父进程读取出来。</p>
              </div>
            </details>

<h2 id="4-管道的大小"><a href="#4-管道的大小" class="headerlink" title="4. 管道的大小"></a><font size=3>4. 管道的大小</font></h2><h3 id="4-1-最多写多少字节？"><a href="#4-1-最多写多少字节？" class="headerlink" title="4.1 最多写多少字节？"></a><font size=3>4.1 最多写多少字节？</font></h3><p>在前边记录<code>Linux</code>管道一节的时候，提到过管道的大小，记得有一个疑问就是一个<code>4k</code>一个<code>16</code>页，是什么意思，管道到底有多大，我们可以写一个测试程序测试一下：</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">/* 定义一个 pid_t 类型变量用于保存进程号*/</span></span><br><span class="line">	<span class="type">pid_t</span> pid;</span><br><span class="line">	<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[0]=%d,pfd[1]=%d\n&quot;</span>,pfd[<span class="number">0</span>],pfd[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 2. 创建一个父子进程 */</span></span><br><span class="line">	pid = fork();</span><br><span class="line">	<span class="comment">/* 3. 父子进程区分执行不同内容 */</span></span><br><span class="line">	<span class="comment">/* 进程创建错误 */</span></span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 父进程 */</span></span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭父进程中管道读取端 */</span></span><br><span class="line">		close(pfd[<span class="number">0</span>]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;count=%d\n&quot;</span>, count++);</span><br><span class="line">			<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line">			ret = write(pfd[<span class="number">1</span>], <span class="string">&quot;a&quot;</span>, <span class="number">1</span>);<span class="comment">/* 每次写入一个字节数据 */</span>	</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 子进程 */</span></span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭子进程中管道的写入端 */</span></span><br><span class="line">		close(pfd[<span class="number">1</span>]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			sleep(<span class="number">100</span>);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">pfd[0]=3,pfd[1]=4</span><br><span class="line">count=0</span><br><span class="line">count=1</span><br><span class="line">count=2</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">中间的省略 ... ...</span></span><br><span class="line">count=65534</span><br><span class="line">count=65535</span><br><span class="line">count=65536</span><br></pre></td></tr></table></figure><p>可以发现，当我们只写不读的时候且<code>count=65536</code>的时候进程就会阻塞等待，这个时候就是管道已经被写满了，我们知道<code>count=0</code>的时候写入第一个字节数据，<code>count=65535</code>的时候写入最后一个数据，大小一共是<code>65536/1024=64K</code>。</p>
              </div>
            </details>

<p>【结论】我使用的环境是<code>Ubuntu21.04</code>的<code>64</code>位版本，测试结果表明，最多可写入<code>64K</code>字节的数据。</p>
<h3 id="4-2-读4k-1个字节？"><a href="#4-2-读4k-1个字节？" class="headerlink" title="4.2 读4k-1个字节？"></a><font size=3>4.2 读<code>4k-1</code>个字节？</font></h3><p>我后来有了这样一个疑问，当管道写满的时候，我读<code>4k</code>个字节以内数据吗，是不是就可以再写入相同数量个字节数据呢？（为啥是<code>4K</code>为分界，可以看本篇笔记的Linux管道——管道大小查看一小节。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">/* 定义一个 pid_t 类型变量用于保存进程号*/</span></span><br><span class="line">	<span class="type">pid_t</span> pid;</span><br><span class="line">	<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[0]=%d,pfd[1]=%d\n&quot;</span>,pfd[<span class="number">0</span>],pfd[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 2. 创建一个父子进程 */</span></span><br><span class="line">	pid = fork();</span><br><span class="line">	<span class="comment">/* 3. 父子进程区分执行不同内容 */</span></span><br><span class="line">	<span class="comment">/* 进程创建错误 */</span></span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 父进程 */</span></span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭父进程中管道读取端 */</span></span><br><span class="line">		close(pfd[<span class="number">0</span>]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;count=%d\n&quot;</span>, count++);</span><br><span class="line">			<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line">			ret = write(pfd[<span class="number">1</span>], <span class="string">&quot;a&quot;</span>, <span class="number">1</span>);<span class="comment">/* 每次写入一个字节数据 */</span></span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;Write %d Byte!\n&quot;</span>, ret);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 子进程 */</span></span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭子进程中管道的写入端 */</span></span><br><span class="line">		close(pfd[<span class="number">1</span>]);</span><br><span class="line">		</span><br><span class="line">		<span class="type">char</span> buff[<span class="number">4</span>*<span class="number">1024</span><span class="number">-1</span>] = &#123;<span class="number">0</span>&#125;; <span class="comment">/* 尝试从管道读取数据为 1Byte*/</span></span><br><span class="line">        sleep(<span class="number">10</span>);</span><br><span class="line">		ret = read(pfd[<span class="number">0</span>], buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">		<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;child read pipe=%s\n&quot;</span>,buff);</span><br><span class="line">		&#125;</span><br><span class="line">		sleep(<span class="number">200</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">pfd[0]=3,pfd[1]=4</span><br><span class="line">count=0</span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=1</span><br><span class="line">Write 1 Byte!</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">中间的省略 ... ...</span></span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=65535</span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=65536</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">10s后新增 ... ... 省略一部分</span></span><br><span class="line">child read pipe=a... ... # (后边的省略)</span><br></pre></td></tr></table></figure><p>可以发现，还是之前的样子，写入到第<code>65536</code>个字节数据的时候，程序阻塞，等过<code>10s</code>后，子进程运行，读取<code>4k-1</code>个字节的数据，但是程序之后继续阻塞，并未有数据写入。</p>
              </div>
            </details>

<p>【结论】管道写满的时候，读取<code>4k</code>以内个字节并不能结束父进程阻塞，依然无法继续写入。</p>
<h3 id="4-3-读4K个字节？"><a href="#4-3-读4K个字节？" class="headerlink" title="4.3 读4K个字节？"></a><font size=3>4.3 读<code>4K</code>个字节？</font></h3><p>我后来有了这样一个疑问，当管道写满的时候，我读<code>4k</code>个字节数据呢？（为啥是<code>4K</code>为分界，可以看本篇笔记的 Linux管道——管道大小查看一小节）</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">/* 定义一个 pid_t 类型变量用于保存进程号*/</span></span><br><span class="line">	<span class="type">pid_t</span> pid;</span><br><span class="line">	<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[0]=%d,pfd[1]=%d\n&quot;</span>,pfd[<span class="number">0</span>],pfd[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 2. 创建一个父子进程 */</span></span><br><span class="line">	pid = fork();</span><br><span class="line">	<span class="comment">/* 3. 父子进程区分执行不同内容 */</span></span><br><span class="line">	<span class="comment">/* 进程创建错误 */</span></span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 父进程 */</span></span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭父进程中管道读取端 */</span></span><br><span class="line">		close(pfd[<span class="number">0</span>]);</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;count=%d\n&quot;</span>, count++);</span><br><span class="line">			<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line">			ret = write(pfd[<span class="number">1</span>], <span class="string">&quot;a&quot;</span>, <span class="number">1</span>);<span class="comment">/* 每次写入一个字节数据 */</span></span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;Write %d Byte!\n&quot;</span>, ret);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 子进程 */</span></span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 关闭子进程中管道的写入端 */</span></span><br><span class="line">		close(pfd[<span class="number">1</span>]);</span><br><span class="line">		</span><br><span class="line">		<span class="type">char</span> buff[<span class="number">4</span>*<span class="number">1024</span>] = &#123;<span class="number">0</span>&#125;; <span class="comment">/* 尝试从管道读取数据为 1Byte*/</span></span><br><span class="line">        sleep(<span class="number">10</span>);</span><br><span class="line">        <span class="comment">// 子进程读数据，但是没有打印读的什么，测试的时候可以吧读的打印出来</span></span><br><span class="line">		ret = read(pfd[<span class="number">0</span>], buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>)); </span><br><span class="line">		<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;child read pipe=%s\n&quot;</span>,buff);</span><br><span class="line">		&#125;</span><br><span class="line">		sleep(<span class="number">200</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">pfd[0]=3,pfd[1]=4</span><br><span class="line">count=0</span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=1</span><br><span class="line">Write 1 Byte!</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">中间的省略 ... ...</span></span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=65535</span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=65536</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">10s后新增 ... ... 省略一部分</span></span><br><span class="line">child read pipe=a... ... # (后边的省略)</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">中间省略 ... ...</span></span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=69631</span><br><span class="line">Write 1 Byte!</span><br><span class="line">count=69632</span><br></pre></td></tr></table></figure><p>可以发现，还是之前的样子，写入到第<code>65536</code>个字节数据的时候，程序阻塞，等过<code>10s</code>后，子进程运行，读取<code>4k</code>个字节的数据，程序之后继续写入到第<code>69632</code>个数据时继续阻塞，这中间写入了<code>69631-65535=4096</code>也就是<code>4k</code>个字节数据。</p>
              </div>
            </details>

<p>【结论】读取数据大于等于<code>4k</code>时，管道才能继续写入相应字节数据。</p>
<h2 id="5-无名管道特性"><a href="#5-无名管道特性" class="headerlink" title="5. 无名管道特性"></a><font size=3>5. 无名管道特性</font></h2><h3 id="5-1-读写端固定"><a href="#5-1-读写端固定" class="headerlink" title="5.1 读写端固定"></a><font size=3>5.1 读写端固定</font></h3><h4 id="5-1-1-说明"><a href="#5-1-1-说明" class="headerlink" title="5.1.1 说明"></a><font size=3>5.1.1 说明</font></h4><p>无名管道的读写段端是固定的：</p>
<table>
    <tr>
        <td align="center" width=150px>pipefd[0]</td>
        <td align="left">管道读端</td>
    </tr>
    <tr>
        <td align="center" width=150>pipefd[1]</td>
        <td align="left">管道写端</td>  
    </tr>
</table>


<p>实际上两个文件描述符，可以有以下四种组合情况（下边的四种情况都是考虑管道中无数据）：</p>
<table>
    <tr><td align="center" width="150px">管道写端     </td><td align="center" width="150px">管道读端      </td><td align="center">出现的情况</td></tr>
    <tr><td align="center" width="150px">pipefd[0](读)</td><td align="center" width="150px">pipefd[0](读) </td><td align="left">读端写，读端读，会阻塞（若管道之前有数据，那么是可以正常被读出来的，但是读完之后会阻塞）</td></tr>
    <tr><td align="center" width="150px">pipefd[0](读)</td><td align="center" width="150px">pipefd[1](写) </td><td align="left">读端写，写端读，会阻塞</td></tr>
    <tr><td align="center" width="150px">pipefd[1](写)</td><td align="center" width="150px">pipefd[0](读) </td><td align="left">写端写，读端读，可以正常读写</td></tr>
    <tr><td align="center" width="150px">pipefd[1](写)</td><td align="center" width="150px">pipefd[1](写) </td><td align="left">写端写，写端读，会一直写入数据，但是无法读取</td></tr>
</table>


<p>【注意事项】</p>
<p>（1）管道中有数据才能读，否则读取就会阻塞，所以我们下边需要保证先写入，后读取，下边是一个示例程序，直接修改测试即可。</p>
<p>（2）由于读写端的固定，这也导致了数据只能单向传输。</p>
<h4 id="5-1-2-测试实例"><a href="#5-1-2-测试实例" class="headerlink" title="5.1.2 测试实例"></a><font size=3>5.1.2 测试实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">char</span> buff[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];</span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[0]=%d,pfd[1]=%d\n&quot;</span>,pfd[<span class="number">0</span>],pfd[<span class="number">1</span>]);</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 拷贝字符串到字符数组 */</span></span><br><span class="line">		<span class="built_in">strcpy</span>(buff,<span class="string">&quot;fanhua&quot;</span>);</span><br><span class="line">		<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line">		ret = write(pfd[<span class="number">1</span>], buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">		<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;write pipe=%s\n&quot;</span>, buff);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">/* 从字符数组中读取数据 */</span></span><br><span class="line">		ret = read(pfd[<span class="number">0</span>], buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">		<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;read pipe=%s\n&quot;</span>, buff);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">/* 休眠1s */</span></span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，查看终端信息显示即可。</p>
              </div>
            </details>

<h3 id="5-2-读管道特性"><a href="#5-2-读管道特性" class="headerlink" title="5.2 读管道特性"></a><font size=3>5.2 读管道特性</font></h3><h4 id="5-2-1-说明"><a href="#5-2-1-说明" class="headerlink" title="5.2.1 说明"></a><font size=3>5.2.1 说明</font></h4><p>这一部分主要是通过实例来得出结论，实例会放在后边，这里先给出结论。对于读管道的特性有两种情况：</p>
<ul>
<li>管道中有数据</li>
</ul>
<p><code>read</code>将返回实际读到的字节数。</p>
<ul>
<li>管道中无数据</li>
</ul>
<p> （1）管道写端被全部关闭时，<code>read</code>返回<code>0</code> (好像读到文件结尾一样)。</p>
<p> （2）写端没有全部被关闭时，<code>read</code>阻塞等待(不久的将来可能有数据递达，此时会让出<code>cpu</code>)</p>
<h4 id="5-2-2-使用实例"><a href="#5-2-2-使用实例" class="headerlink" title="5.2.2 使用实例"></a><font size=3>5.2.2 使用实例</font></h4><p>上边两种情况的验证，可以看下边的实例。</p>
<details class="folding-tag" blue><summary> 点击查看实例源码 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> READPIPE 0  <span class="comment">/* 管道读 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> WRITEPIPE 1 <span class="comment">/* 管道写 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 注意写端关闭则无法写入数据 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_PFD 0   <span class="comment">/* 0,不关闭父进程写端，1,关闭父进程写端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_DATA 1  <span class="comment">/* 0,父进程不写入数据，1,父进程5s写入一次数据 */</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">char</span> buff[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="type">pid_t</span> pid;  <span class="comment">/* 定义一个 pid_t 类型变量用于保存进程号*/</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>]; <span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[READPIPE]=%d,pfd[WRITEPIPE]=%d\n&quot;</span>,pfd[READPIPE],pfd[WRITEPIPE]);</span><br><span class="line">	<span class="comment">/* 2. 创建一个父子进程 */</span></span><br><span class="line">	pid = fork();</span><br><span class="line">	<span class="comment">/* 3. 父子进程区分执行不同内容 */</span></span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)<span class="comment">/* 进程创建错误 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)<span class="comment">/* 父进程 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		close(pfd[READPIPE]); <span class="comment">/* 关闭父进程中管道读取端 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> F_WRITE_PFD == 1</span></span><br><span class="line">		close(pfd[WRITEPIPE]);<span class="comment">/* 关闭父进程中管道写入端 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>, ++i);</span><br><span class="line">			<span class="built_in">strcpy</span>(buff,<span class="string">&quot;fanhua&quot;</span>); <span class="comment">/* 拷贝字符串到字符数组 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> F_WRITE_DATA == 1</span></span><br><span class="line">			<span class="keyword">if</span>(i%<span class="number">5</span> == <span class="number">0</span>)</span><br><span class="line">				write(pfd[WRITEPIPE], buff, <span class="built_in">strlen</span>(buff));<span class="comment">/* 向字符数组写入数据 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">			sleep(<span class="number">1</span>);<span class="comment">/* 休眠1s */</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 子进程 */</span></span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">	&#123;</span><br><span class="line">		</span><br><span class="line">		close(pfd[WRITEPIPE]);<span class="comment">/* 关闭子进程中管道的写入端 */</span></span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="comment">/* 从字符数组中读取数据 */</span></span><br><span class="line">			ret = read(pfd[READPIPE], buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">			<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(<span class="string">&quot;child read pipe=%s, ret = %d\n&quot;</span>, buff, ret);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="keyword">else</span> <span class="keyword">if</span>(ret == <span class="number">0</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(<span class="string">&quot; ret = %d\n&quot;</span>, ret);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p>上面有两个宏定义，分别代表的含义如下：</p>
<table>
    <tr><td align="center" width=150px>F_WRITE_PFD</td><td align="left">0,不关闭父进程写端，1,关闭父进程写端</td></tr>
    <tr><td align="center" width=150px>F_WRITE_DATA</td><td align="left">0,父进程不写入数据，1,父进程5s写入一次数据</td></tr>
</table>


<p>在父子进程中，子进程用于读取数据，所以子进程原本就关闭了自己的管道写入端，还剩下管道读取端；父进程用于写入数据，所以父进程原本就关闭了自己的读取端，还剩下管道写入端。</p>
<p>宏<code>F_WRITE_PFD</code>就决定父进程是否关闭自己的写入端，选择关闭时，整个管道的写入端关闭，无法再写入数据。</p>
<p>宏<code>F_WRITE_DATA</code>决定了父进程中是否写入数据，但是当写端全部关闭时，即便在父进程中开启了数据写入，也不会有数据写到管道中。</p>
<p><strong>【结论的验证与宏的对应情况】</strong></p>
<ul>
<li>管道中有数据</li>
</ul>
<p><code>read</code>将返回实际读到的字节数。此条结论对应宏的情况如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_PFD 0   <span class="comment">/* 0,不关闭父进程写端，1,关闭父进程写端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_DATA 1  <span class="comment">/* 0,父进程不写入数据，1,父进程5s写入一次数据 */</span></span></span><br></pre></td></tr></table></figure>

<ul>
<li>管道中无数据</li>
</ul>
<p> （1）管道写端被全部关闭时，<code>read</code>返回<code>0</code> (好像读到文件结尾一样)。此条结论对应宏的情况如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_PFD 1   <span class="comment">/* 0,不关闭父进程写端，1,关闭父进程写端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_DATA 0  <span class="comment">/* 0,父进程不写入数据，1,父进程5s写入一次数据 */</span></span></span><br></pre></td></tr></table></figure>

<p>这种情况下，<code>F_WRITE_DATA</code>的值并没有什么意义，因为写端已经关闭了，不管是否有写入数据的部分，管道中都不会有数据写入。</p>
<p> （2）写端没有全部被关闭时，<code>read</code>阻塞等待(不久的将来可能有数据递达，此时会让出<code>cpu</code>)。此条结论对应宏的情况如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_PFD 0   <span class="comment">/* 0,不关闭父进程写端，1,关闭父进程写端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> F_WRITE_DATA 0  <span class="comment">/* 0,父进程不写入数据，1,父进程5s写入一次数据 */</span></span></span><br></pre></td></tr></table></figure>

<p><code>F_WRITE_DATA</code>为<code>0</code>时，将会一直等待读取，而为<code>1</code>时，只要有数据写入就会被读取。</p>
<h3 id="5-3-写管道特性"><a href="#5-3-写管道特性" class="headerlink" title="5.3 写管道特性"></a><font size=3>5.3 写管道特性</font></h3><h4 id="5-3-1-说明"><a href="#5-3-1-说明" class="headerlink" title="5.3.1 说明"></a><font size=3>5.3.1 说明</font></h4><p>对于写管道的特性有两种情况：</p>
<ul>
<li>管道读端全部被关闭</li>
</ul>
<p>进程异常终止(也可使用捕捉<code>SIGPIPE</code>信号，使进程不终止)。</p>
<ul>
<li>管道读端没有全部关闭</li>
</ul>
<p>（1）管道已满，<code>write</code>阻塞。（管道大小<code>64K</code>，不过也不一定，也可以使用相关命令查看，本篇笔记前边的管道数据大小查看有提过）</p>
<p>（2）管道未满，<code>write</code>将数据写入，并返回实际写入的字节数。</p>
<h4 id="5-3-2-使用实例"><a href="#5-3-2-使用实例" class="headerlink" title="5.3.2 使用实例"></a><font size=3>5.3.2 使用实例</font></h4><p>上边两种情况的验证，可以看下边的实例。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork pipe read write close*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strcpy strlen */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span> <span class="comment">/* exit */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> READPIPE 0  <span class="comment">/* 管道读 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> WRITEPIPE 1 <span class="comment">/* 管道写 */</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> C_READ_PFD 0  <span class="comment">/* 0,不关闭子进程读端，1,关闭子进程读端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PIPE_FULL 0   <span class="comment">/* 0,不将管道写满，1,将管道写满 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> PIPE_FULL == 1</span></span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> j = <span class="number">1</span>;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="type">char</span> buff[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="type">pid_t</span> pid;<span class="comment">/* 定义一个 pid_t 类型变量用于保存进程号*/</span></span><br><span class="line">	<span class="type">int</span> pfd[<span class="number">2</span>];<span class="comment">/* 定义读写管道数组 */</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1. 创建管道 */</span></span><br><span class="line">	ret = pipe(pfd);</span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;pipe&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;pfd[READPIPE]=%d,pfd[WRITEPIPE]=%d\n&quot;</span>,pfd[READPIPE],pfd[WRITEPIPE]);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 2. 创建一个父子进程 */</span></span><br><span class="line">	pid = fork();</span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)<span class="comment">/* 进程创建错误 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)<span class="comment">/* 父进程 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		close(pfd[READPIPE]); <span class="comment">/* 关闭父进程中管道读取端 */</span></span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line"></span><br><span class="line">			<span class="built_in">strcpy</span>(buff,<span class="string">&quot;fanhua！&quot;</span>);<span class="comment">/* 拷贝字符串到字符数组 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> PIPE_FULL == 1</span></span><br><span class="line">			<span class="keyword">for</span>(i = <span class="number">0</span>; i&lt;<span class="number">1000</span>; i++)<span class="comment">/* 向字符数组写入数据(写满) */</span></span><br><span class="line">			&#123;</span><br><span class="line">				write(pfd[WRITEPIPE], buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;Write %d times!\n&quot;</span>, j);</span><br><span class="line">			j++;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">			ret = write(pfd[WRITEPIPE], buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;Write %d Byte!\n&quot;</span>, ret);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">			<span class="comment">/* 休眠1s */</span></span><br><span class="line">			sleep(<span class="number">1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span><span class="comment">/* 子进程 */</span></span><br><span class="line">	&#123;</span><br><span class="line"></span><br><span class="line">		close(pfd[WRITEPIPE]);<span class="comment">/* 关闭子进程中管道的写入端 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> C_READ_PFD == 1</span></span><br><span class="line">		close(pfd[READPIPE]); <span class="comment">/* 关闭子进程中管道读取端 */</span></span><br><span class="line">		sleep(<span class="number">3</span>);</span><br><span class="line">		<span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			ret = read(pfd[READPIPE], buff, <span class="keyword">sizeof</span>(buff)/<span class="keyword">sizeof</span>(<span class="type">char</span>));</span><br><span class="line">			<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(<span class="string">&quot;child read pipe=%s, ret = %d\n&quot;</span>, buff, ret);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p>上面有两个宏定义，分别代表的含义如下：</p>
<table>
    <tr><td align="center" width=150px>C_READ_PFD</td><td align="left">0,不关闭子进程读端，1,关闭子进程读端</td></tr>
    <tr><td align="center" width=150px>PIPE_FULL</td><td align="left">0,不将管道写满，1,将管道写满</td></tr>
</table>

<p>在父子进程中，子进程用于读取数据，所以子进程原本就关闭了自己的管道写入端，还剩下管道读取端；父进程用于写入数据，所以父进程原本就关闭了自己的读取端，还剩下管道写入端。</p>
<p>宏<code>C_READ_PFD</code>就决定子进程是否关闭自己的读取端，选择关闭时，整个管道的读取端关闭，无法再读取数据。</p>
<p>宏<code>PIPE_FULL</code>决定了父进程中是否写入数据直到管道写满。</p>
<p><strong>【结论的验证与宏的对应情况】</strong></p>
<ul>
<li>管道读端全部被关闭</li>
</ul>
<p>进程异常终止(也可使用捕捉<code>SIGPIPE</code>信号，使进程不终止)。此条结论对应宏的情况如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> C_READ_PFD 1  <span class="comment">/* 0,不关闭子进程读端，1,关闭子进程读端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PIPE_FULL 0   <span class="comment">/* 0,不将管道写满，1,将管道写满 */</span></span></span><br></pre></td></tr></table></figure>

<p>这种情况下，程序在写入一次后就终止了。</p>
<ul>
<li>管道读端没有全部关闭</li>
</ul>
<p>（1）管道已满，<code>write</code>阻塞。（管道大小<code>64K</code>，不过也不一定，也可以使用相关命令查看，本篇笔记前边的管道数据大小查看有提过）</p>
<p>此条结论对应宏的情况如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> C_READ_PFD 0  <span class="comment">/* 0,不关闭子进程读端，1,关闭子进程读端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PIPE_FULL 1   <span class="comment">/* 0,不将管道写满，1,将管道写满 */</span></span></span><br></pre></td></tr></table></figure>

<p>这种情况下其实与上边测试管道大小的的时候是一样的，管道只写不读，当管道写满后程序开始阻塞。若想继续写入，则需要读取管道中至少<code>4k</code>字节的数据才能写入。</p>
<p>（2）管道未满，<code>write</code>将数据写入，并返回实际写入的字节数。此条结论对应宏的情况如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> C_READ_PFD 0  <span class="comment">/* 0,不关闭子进程读端，1,关闭子进程读端 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PIPE_FULL 0   <span class="comment">/* 0,不将管道写满，1,将管道写满 */</span></span></span><br></pre></td></tr></table></figure>

<p>这种情况下，就是正常的写入读取操作。</p>
<h1 id="四、有名管道"><a href="#四、有名管道" class="headerlink" title="四、有名管道"></a><font size=3>四、有名管道</font></h1><p>有名管道主要用于<strong>非亲缘的两个进程互相通信</strong>。</p>
<h2 id="1-有名管道创建"><a href="#1-有名管道创建" class="headerlink" title="1. 有名管道创建"></a><font size=3>1. 有名管道创建</font></h2><h3 id="1-1-mkfifo"><a href="#1-1-mkfifo" class="headerlink" title="1.1 mkfifo() "></a><font size=3>1.1 mkfifo() </font></h3><h4 id="1-1-1-函数说明-1"><a href="#1-1-1-函数说明-1" class="headerlink" title="1.1.1 函数说明"></a><font size=3>1.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 3 mkfifo </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">mkfifo</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *pathname, <span class="type">mode_t</span> mode)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于创建一个有名管道，创建的有名管道文件也可以称为<code>FIFO</code>文件。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>pathname</code>：<code>const char *</code>类型，有名管道文件存放的路径（包括管道名称），需要注意的是，这里不要放在共享目录下。</li>
<li><code>mode</code>：<code>mode_t</code>类型，有名管道文件权限，为<code>8</code>进制表示法。新建的有名管道文件权限会受到<code>umask</code> 值影响，实际权限是<code>mode - umaks</code>。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看什么是 umask </summary>
              <div class='content'>
              <p>在类<code>unix</code>系统中，<code>umask</code>是确定掩码设置的命令，该掩码用来设定文件或目录的初始权限。<code>umask</code>确定了文件创建时的初始权限:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">文件或目录的初始权限 = 文件或目录的最大默认权限 - umask权限</span><br></pre></td></tr></table></figure><p>文件初始默认权限为<code>0666</code>，目录为<code>0777</code>，若用户<code>umask</code>为<code>0002</code>，则新创建的文件或目录在没有指定的情况下默认权限分别为<code>0664</code>、<code>0775</code>)。</p><p>在<code>Linux</code>下，我们可以使用<code>umask</code>命令来查看当前用户默认的<code>umask</code>值，同时也可以在<code>umask</code>命令后面跟上需要设置的<code>umask</code>值来重新设置<code>umask</code>。</p>
              </div>
            </details>

<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">mkfifo(<span class="string">&quot;/home/hk/MyFifo&quot;</span>, <span class="number">0666</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）文件路径不要定在虚拟机中<code>Linux</code>与<code>Windows</code>的共享目录中。</p>
<p>（2）该文件必须不存在。</p>
<h4 id="1-1-2-使用实例-1"><a href="#1-1-2-使用实例-1" class="headerlink" title="1.1.2 使用实例"></a><font size=3>1.1.2 使用实例</font></h4><p>暂无。</p>
<h2 id="2-有名管道打开"><a href="#2-有名管道打开" class="headerlink" title="2. 有名管道打开"></a><font size=3>2. 有名管道打开</font></h2><h3 id="2-1-open"><a href="#2-1-open" class="headerlink" title="2.1 open() "></a><font size=3>2.1 open() </font></h3><h4 id="2-1-1-函数说明-1"><a href="#2-1-1-函数说明-1" class="headerlink" title="2.1.1 函数说明"></a><font size=3>2.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 open </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">open</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *pathname, <span class="type">int</span> flags)</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">open</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *pathname, <span class="type">int</span> flags, <span class="type">mode_t</span> mode)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>pathname</code>：<code>const char *</code>类型，表示需要被打开的文件名（可包括路径名）。</li>
<li><code>flags</code>：<code>int</code>类型，表示打开文件所采用的操作。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看详细的 flag 常量 </summary>
              <div class='content'>
              <ul><li><code>flag</code> 常量常见可取的值</li></ul><table>    <tr><td align="center" width=150px>O_RDONLY</td><td align="left">只读方式打开文件。</td><td align="left" rowspan=3>这三个参数互斥</td></tr>    <tr><td align="center" width=150px>O_WRONLY</td><td align="left" >可写方式打开文件。</td></tr>    <tr><td align="center" width=150px>O_RDWR  </td><td align="left">读写方式打开文件。</td></tr>    <tr><td align="center" width=150px>O_CREAT </td><td align="left" colspan=2>如果该文件不存在，就创建一个新的文件，并用第三的参数为其设置权限。</td></tr>    <tr><td align="center" width=150px>O_EXCL  </td><td align="left" colspan=2>如果使用O_CREAT时文件存在，则可返回错误消息。这一参数可测试文件是否存在。</td></tr>    <tr><td align="center" width=150px>O_NOCTTY</td><td align="left" colspan=2>使用本参数时，如文件为终端，那么终端不可以作为调用open()系统调用的那个进程的控制终端。</td></tr>    <tr><td align="center" width=150px>O_TRUNC </td><td align="left" colspan=2>如文件已经存在，那么打开文件时先删除文件中原有数据。</td></tr>    <tr><td align="center" width=150px>O_APPEND</td><td align="left" colspan=2>以添加方式打开文件，所以对文件的写操作都在文件的末尾进行。</td></tr>    <tr><td align="center" width=150px>O_NONBLOCK</td><td align="left" colspan=2>以非阻塞的方式打开文件。</td></tr></table><p>【注意事项】前三个参数必须指定，且只能指定一个，后边的几个可以与前边搭配使用。</p><ul><li><code>flag</code>常量与标准<code>I/O</code>文件打开权限关系、</li></ul><table>    <tr><td align="center" width=150px>r </td><td align="left" colspan=2>O_RDONLY</td></tr>    <tr><td align="center" width=150px>r+</td><td align="left" colspan=2>O_RDWR</td></tr>    <tr><td align="center" width=150px>w </td><td align="left" colspan=2>O_WRONLY | O_CREAT | O_TRUNC, 0664</td></tr>    <tr><td align="center" width=150px>w+</td><td align="left" colspan=2>O_RDWR | O_CREAT | O_TRUNC, 0664</td></tr>    <tr><td align="center" width=150px>a </td><td align="left" colspan=2>O_WRONLY | O_CREAT | O_APPEND, 0664</td></tr>    <tr><td align="center" width=150px>a+</td><td align="left" colspan=2>O_RDWR | O_CREAT | O_APPEND, 0664</td></tr></table>
              </div>
            </details>

<ul>
<li><code>mode</code>：<code>mode_t</code>类型，表示被打开文件的存取权限，为<code>8</code>进制表示法。此参数<strong>只有在建立新文件时有效</strong>。新建文件时的权限会受到<code>umask</code> 值影响，实际权限是<code>mode - umaks</code>。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功时返回文件描述符(非负整数)；出错时返回<code>EOF</code>（一般是<code>-1</code>）。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> fd;<span class="comment">/* 接收文件描述符 */</span></span><br><span class="line"><span class="comment">/* 以只写方式打开文件file.txt。如果文件不存在则创建，如果文件存在则清空 */</span></span><br><span class="line">fd = open(<span class="string">&quot;file.txt&quot;</span>, O_WRONLY | O_CREAT | O_TRUNC, <span class="number">0666</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>该函数可以打开设备文件，但是不<strong>能创建设备文件</strong>。</p>
<h3 id="2-2-使用说明"><a href="#2-2-使用说明" class="headerlink" title="2.2 使用说明"></a><font size=3>2.2 使用说明</font></h3><p>此函数是文件<code>IO</code>中的相关函数，在对有名管道文件进行操作时，需要注意以下几点：</p>
<p>（1）程序不能以<code>O_RDWR</code>(读写)模式打开<code>FIFO</code>文件进行读写操作，而其行为也未明确定义，因为如一个管道以读&#x2F;写方式打开，进程可以读回自己的输出，同时我们通常使用<code>FIFO</code>只是为了单向的数据传递。</p>
<p>（2）<code>open</code>函数的打开方式还可以有以下情况的搭配：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">open(<span class="type">const</span> <span class="type">char</span> *path, O_RDONLY);             <span class="comment">//1</span></span><br><span class="line">open(<span class="type">const</span> <span class="type">char</span> *path, O_RDONLY | O_NONBLOCK);<span class="comment">//2</span></span><br><span class="line">open(<span class="type">const</span> <span class="type">char</span> *path, O_WRONLY);             <span class="comment">//3</span></span><br><span class="line">open(<span class="type">const</span> <span class="type">char</span> *path, O_WRONLY | O_NONBLOCK);<span class="comment">//4</span></span><br></pre></td></tr></table></figure>

<p>第二个参数中的选项<code>O_NONBLOCK</code>，选项<code>O_NONBLOCK</code>表示非阻塞，加上这个选项后，表示<code>open</code>调用是非阻塞的，如果没有这个选项，则表示<code>open</code>调用是阻塞的。</p>
<p>（3）对于以只读方式（<code>O_RDONLY</code>）打开的<code>FIFO</code>文件，如果<code>open</code>调用是阻塞的（即第二个参数为<code>O_RDONLY</code>），除非有一个进程以写方式打开同一个<code>FIFO</code>，否则它不会返回；如果<code>open</code>调用是非阻塞的的（即第二个参数为<code>O_RDONLY | O_NONBLOCK</code>），则即使没有其他进程以写方式打开同一个<code>FIFO</code>文件，<code>open</code>调用将成功并立即返回。</p>
<p>（4）对于以只写方式（<code>O_WRONLY</code>）打开的<code>FIFO</code>文件，如果<code>open</code>调用是阻塞的（即第二个参数为<code>O_WRONLY</code>），<code>open</code>调用将被阻塞，直到有一个进程以只读方式打开同一个<code>FIFO</code>文件为止；如果<code>open</code>调用是非阻塞的（即第二个参数为<code>O_WRONLY | O_NONBLOCK</code>），<code>open</code>总会立即返回，但如果没有其他进程以只读方式打开同一个<code>FIFO</code>文件，<code>open</code>调用将返回<code>-1</code>，并且<code>FIFO</code>也不会被打开。</p>
<p>（5）据完整性,如果有多个进程写同一个管道，使用<code>O_WRONLY</code>方式打开管道，如果写入的数据长度小于等于<code>PIPE_BUF（4K）</code>，或者写入全部字节，或者一个字节都不写入，这样系统就可以确保数据决不会交错在一起。</p>
<h2 id="3-有名管道读写"><a href="#3-有名管道读写" class="headerlink" title="3. 有名管道读写"></a><font size=3>3. 有名管道读写</font></h2><h3 id="3-1-读写函数"><a href="#3-1-读写函数" class="headerlink" title="3.1 读写函数"></a><font size=3>3.1 读写函数</font></h3><p>先说一下读写吧，有名管道的读写与无名管道一样，当打开之后，可以通过<code>read</code>函数读取管道中的数据，可以使用<code>write</code>函数来写入数据。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">read</span><span class="params">(<span class="type">int</span> fildes, <span class="type">void</span> *buf, <span class="type">size_t</span> nbyte)</span>;        <span class="comment">/* 数据读取 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">write</span><span class="params">(<span class="type">int</span> fildes, <span class="type">const</span> <span class="type">void</span> *buf, <span class="type">size_t</span> nbyte)</span>; <span class="comment">/* 数据写入 */</span></span><br></pre></td></tr></table></figure>

<h3 id="3-2-使用实例"><a href="#3-2-使用实例" class="headerlink" title="3.2 使用实例"></a><font size=3>3.2 使用实例</font></h3><p>下边的实例实现了两个进程的通信。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <div class="tabs" id="tabname2"><ul class="nav-tabs"><li class="tab active"><a href="#tabname2-1">fifo_read.c</a></li><li class="tab"><a href="#tabname2-2">fifo_write.c</a></li><li class="tab"><a href="#tabname2-3">Makefile</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname2-1"><p>【说明】对于以只读方式（<code>O_RDONLY</code>）打开的<code>FIFO</code>文件：如果<code>open</code>调用是阻塞的（即第二个参数为<code>O_RDONLY</code>），除非有一个进程以写方式打开同一个<code>FIFO</code>，否则它不会返回；如果<code>open</code>调用是非阻塞的的（即第二个参数为<code>O_RDONLY | O_NONBLOCK</code>），则即使没有其他进程以写方式打开同一个<code>FIFO</code>文件，<code>open</code>调用将成功并立即返回。 </p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror fgets */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* write */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span><span class="comment">/* mkfifo open */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span> <span class="comment">/* mkfifo open */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;fcntl.h&gt;</span>    <span class="comment">/* open */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span>   <span class="comment">/* exit */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">int</span> fd;</span><br><span class="line">	<span class="type">char</span> buff[<span class="number">32</span>];</span><br><span class="line"></span><br><span class="line">	fd = open(<span class="string">&quot;/home/hk/MyFifo&quot;</span>, O_RDONLY);</span><br><span class="line">	<span class="keyword">if</span>(fd &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;open&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;after open MyFifo!\n&quot;</span>);</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">memset</span>(buff, <span class="number">0</span>, <span class="number">32</span>);</span><br><span class="line">		ret = read(fd, buff, <span class="number">32</span>);</span><br><span class="line">		<span class="keyword">if</span>(ret &gt; <span class="number">0</span>)</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;read fifo=%s\n&quot;</span>,buff);</span><br><span class="line">		<span class="keyword">else</span> <span class="keyword">if</span>(ret == <span class="number">0</span>)</span><br><span class="line">			<span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname2-2"><p>【说明】对于以只写方式（<code>O_WRONLY</code>）打开的<code>FIFO</code>文件，如果<code>open</code>调用是阻塞的（即第二个参数为<code>O_WRONLY</code>），<code>open</code>调用将被阻塞，直到有一个进程以只读方式打开同一个<code>FIFO</code>文件为止；如果<code>open</code>调用是非阻塞的（即第二个参数为<code>O_WRONLY | O_NONBLOCK</code>），<code>open</code>总会立即返回，但如果没有其他进程以只读方式打开同一个<code>FIFO</code>文件，<code>open</code>调用将返回<code>-1</code>，并且<code>FIFO</code>也不会被打开。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror fgets */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* write */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strlen */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span><span class="comment">/* mkfifo open */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span> <span class="comment">/* mkfifo open */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;fcntl.h&gt;</span>    <span class="comment">/* open */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">int</span> fd;</span><br><span class="line">	<span class="type">char</span> buff[<span class="number">32</span>];</span><br><span class="line">	<span class="comment">/* 1. 创建有名管道文件 */</span></span><br><span class="line">	ret = mkfifo(<span class="string">&quot;/home/hk/MyFifo&quot;</span>, <span class="number">0666</span>);<span class="comment">/* 注意不要创建在共享目录 */</span></span><br><span class="line">	<span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 若文件已存在，则打印出错信息即可，程序不需要结束 */</span></span><br><span class="line">		perror(<span class="string">&quot;mkfifo&quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 2. 使用文件IO打开有名管道文件 */</span></span><br><span class="line">	fd = open(<span class="string">&quot;/home/hk/MyFifo&quot;</span>, O_WRONLY|O_NONBLOCK);</span><br><span class="line">	<span class="keyword">if</span>(fd &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;open&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;after open MyFifo!\n&quot;</span>);</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		fgets(buff, <span class="number">32</span>, <span class="built_in">stdin</span>);</span><br><span class="line">		write(fd, buff, <span class="built_in">strlen</span>(buff));</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname2-3"><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">CC = gcc</span><br><span class="line"></span><br><span class="line">DEBUG = -g -O2 -Wall</span><br><span class="line">CFLAGS += <span class="variable">$(DEBUG)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 所有.c文件去掉后缀</span></span><br><span class="line">TARGET_LIST = $&#123;patsubst %.c, %, $&#123;wildcard *.c&#125;&#125; </span><br><span class="line"></span><br><span class="line">all : <span class="variable">$(TARGET_LIST)</span></span><br><span class="line"></span><br><span class="line">%.o : %.c</span><br><span class="line">	<span class="variable">$(CC)</span> <span class="variable">$(CFLAGS)</span> -c <span class="variable">$&lt;</span> -o <span class="variable">$@</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="keyword">.PHONY</span>: all clean clean_o</span></span><br><span class="line">clean : clean_o</span><br><span class="line">	@rm -vf <span class="variable">$(TARGET_LIST)</span> </span><br><span class="line">	</span><br><span class="line">clean_o :</span><br><span class="line">	@rm -vf *.o</span><br></pre></td></tr></table></figure></div></div></div><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make # 编译程序，将会生成两个可执行程序 </span><br><span class="line">./fifo_write # 一个终端向管道写入数据</span><br><span class="line">./fifo_read  # 在另一个终端读取管道数据</span><br></pre></td></tr></table></figure><p>然后，两个终端都会阻塞等待另一个进程打开有名管到文件，之后我们在运行写入管道可执行程序的终端中输入数据，便可以在另一个终端中收到了。</p>
              </div>
            </details>

<p>【注意事项】需要注意的是，尽量不要设置不阻塞，否则现象并不明显，很可能会出现以下问题：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open: No such device or address</span><br></pre></td></tr></table></figure>


    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/3873081f.html">LV05-05-进程通信-02-管道</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2023年07月02日 - 21:52</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/3873081f.html" title="LV05-05-进程通信-02-管道">https://sumumm.github.io/post/3873081f.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" rel="tag"><i class="fa fa-tag"></i> LV05-操作系统</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/8457f426.html" rel="prev" title="LV05-05-进程通信-03-信号">
                  <i class="fa fa-angle-left"></i> LV05-05-进程通信-03-信号
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/11a113f5.html" rel="next" title="LV05-05-进程通信-01-进程通信概述">
                  LV05-05-进程通信-01-进程通信概述 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
